只分析ctrl

source("tianfengRwrappers.R")

Ctrl

umap

Return:

umap_plot

markers overview

Return:

markers_heatmap

ctrl.markers <- FindAllMarkers(ctrl, min.pct = 0.1, 
                                    logfc.threshold = 0.5, only.pos = T)
top5markers <- ctrl.markers %>% group_by(cluster) %>% slice_max(n = 5, order_by = avg_logFC)
markers_heatmap <- dhm(top5markers$gene, ctrl)
(markers_heatmap + theme(axis.text = element_text(size= 14, color = "black")))%>%
  ggsave(filename = "./ctrl_only/ctrl_markergene.png", device = png, height = 9, width = 16, plot = .) 

dotplot

top3markers <- ctrl.markers %>% group_by(cluster) %>% slice_max(n = 3, order_by = avg_logFC)
# dotplot <- DotPlot(ctrl, features = top3markers$gene, cols = c("lightgrey","#ff2121")) + coord_flip() + RotatedAxis() + theme_classic() #用来获得白色 而不是透明的背景

dotplot <- Dotplot(top3markers$gene[!duplicated(top3markers$gene)], ctrl) + coord_flip()

##单个基因featureplot ### Return: gene_plot

gene_plot <- f("Gasp",ctrl)
#ggsave(filename = paste0(gene_name,".svg"), device = svg, height = 5, width = 6, plot = gene_plot) #对svg调整坐标轴

##两个基因umap共定位 ### Return: doublegene_featureplot

gene_name <- c("Tom","peb")
p <- doublegene_featureplot(gene_name, ctrl)
ggsave(filename = paste0(gene_name[1],"vs",gene_name[2],".png"), device = png, height = 5, width = 20, plot = p) #对svg调整坐标轴

多基因堆叠小提琴图

Return:

violin_plot

violin_plot(c("salm","kni","Dl","ct","wg","vn","bs"),ctrl) %>%
  ggsave(filename = paste0("violinplot.png"), device = png, height = 5, width = 5, plot = .)

多图featureplot

Return:

mulit_featureplot

gene_name <- c("bnl", "btl", "htl", "Egfr") #可视化的基因名称
multi_featureplot(gene_name, ctrl) %>% ggsave(paste0("./ctrl_only/",as.character(gene_name), ".png"),device = png, width = 6, height = 5, plot = .)

multi_featureplot(c("upd2","dome","PlexA","PlexB"), ctrl) %>% ggsave("./ctrl_only/upd2dome.png",device = png,height = 6, width = 7, plot = .)

multi_featureplot(c("Sema5c","Sema1a","Sema2a","Sema1b"), ctrl)%>% ggsave("./ctrl_only/sema.png",device = png,height = 6, width = 7, plot = .)

multi_featureplot(c("peb","Dad","dpp","ex"),ctrl) %>% ggsave("./ctrl_only/pebDadex.png",device = png,height = 6, width = 7, plot = .)

转录因子 SCENIC

Return:

TFheatmap

regulonActivity <- read.csv("./regulonActivity.csv",row.names = 1)
topTFs <- read.csv("./topRegulators.csv")
top5 <- topTFs %>% group_by(seuratCluster) %>% slice_max(n = 5, order_by = RelativeActivity)

#根据已知的top5更新行顺序
regulonActivity <- regulonActivity[sapply(top5$Regulon, function(e) {which(rownames(regulonActivity) == e)}), ]
#annotation_col <-  data.frame(cluster = factor(top5$seuratCluster), row.names = make.names(top5$Regulon,TRUE)) #make.names用来生成不冲突的行
regulonActivity <- regulonActivity[,c("DB","DT","NE","PC","SB","TC","VB")]

TFheatmap <- pheatmap(regulonActivity, breaks = unique(c(seq(-3,3, length=400))), 
                 color = colorRampPalette(c("#1E90FF", "white", "#ff2121"))(400),
                border_color = NA, cluster_rows = FALSE, cluster_cols = FALSE,
                main = "regulonActivity",angle_col = 45, show_rownames = T)
#ggsave(filename = paste0("regulonActivity",".svg"), device = svg, height = 8, width = 12, plot = TFheatmap)

pseudotime featureplot

Return:

pseudotime in featurePlot

pseudotimePlot <- f("pseudotime", cols = c("hotpink","#1E90FF"))
#ggsave(filename = paste0("pt_featureplot2",".svg"), device = svg, height = 5, width = 6, plot = pseudotimePlot)

基因+拟时

Return:

genewithpseudotime

datMat <- as.matrix(GetAssayData(ctrl,slot = "data"))
df <- data.frame(t(ctrl$pseudotime))
df <- do.call(data.frame,lapply(df, function(x){
  x = x/20
  replace(x, is.infinite(x),0)}))
rownames(df) <- "pseudotime"
colnames(df) <- colnames(datMat)
datMat <- rbind(df, datMat)

test <- CreateSeuratObject(counts = datMat)
test@reductions[["umap"]] <- ctrl@reductions[["umap"]]
test@active.ident <- ctrl@active.ident
# SetAssayData(ctrl,slot = "data", new.data = datMat)
#共定位
gene_name <- c("Tom","pseudotime")
genewithpseudotime <- FeaturePlot(test, pt.size = 0.8, slot = "counts",min.cutoff = 0, max.cutoff = 4, features = gene_name, cols = c("lightgrey","#1E90FF", "#ff2121"), label = TRUE, blend = T, blend.threshold = 0) + theme(axis.line = element_blank(), axis.text = element_blank(), axis.ticks = element_blank(), axis.title = element_blank())
#ggsave(filename = paste0(gene_name[1],"vs",gene_name[2],".png"), device = png, height = 5, width = 20, plot = genewithpseudotime)

基因拟时表达

Return:

pseudotime_cells pseudotime_bins pseudotime_ridges pseudotime_ridges2

#选取细胞亚群进行分析
cell.subset <- subset(x = ctrl,idents = c("DT","SB"),invert = FALSE )
nbins <-  15
cell.subset <- make_bins(cell.subset,nbins)
top_specific_marker_ids <- readRDS("top_specific_marker_ids.RDS")
pseudotime_cells <- make_pseudotime_heatmap_bycells(cell.subset,top_specific_marker_ids,50)
#ggsave(filename = "pseudotime_heatmap_bycells.png", device = png, height = 6, width = 10, plot = pseudotime_cells)

pseudotime_bins <- make_pseudotime_heatmap_average(cell.subset,top_specific_marker_ids,50)
#ggsave(filename = "pseudotime_heatmap_bins.png", device = png, height = 6, width = 10, plot = pseudotime_bins)

df <- get_draw(ctrl, genelist = head(top_specific_marker_ids,10), expr_threshold = 1)

pseudotime_ridges <- ggplot(df, aes(x = pseudotime , y = gene , fill = gene)) +
 ggridges::geom_density_ridges(alpha = 0.5,show.legend =T) + labs(title = 'DEGs with pseudotime')+
 theme_ipsum() +  theme(legend.position="none", panel.spacing = unit(0.1, "lines"),
                        strip.text.x = element_text(size = 8))
#ggsave(filename = "pseudotime_ridges.png", device = png, height = 8, width = 10, plot = pseudotime_ridges)

pseudotime_ridges2 <- ggplot(df, aes(x = pseudotime, y = gene, fill = ..x..))  +
  geom_density_ridges_gradient(scale = 3, rel_min_height = 0.01,alpha = 0.5) +
  scale_fill_viridis(name = ctrl$pseudotime, option = "C") +
  labs(title = 'DEGs with pseudotime') + theme_ipsum() +
    theme(
      legend.position="none",
      panel.spacing = unit(0.1, "lines"),
      strip.text.x = element_text(size = 8))
##ggsave(filename = "pseudotime_ridges2.jpg", device = jpeg, height = 8, width = 10, plot = pseudotime_ridges2)

GO

Return:

GO_plot

library(org.Dm.eg.db)
for (cl in levels(Idents(ctrl))){
  #选择cluster对应的marker
  gene_list <- ctrl.markers[ctrl.markers$cluster==cl,]$gene
  #ID转换
  genes <- bitr(gene_list, fromType="SYMBOL",toType=c("ENTREZID","ENSEMBL"),
                   OrgDb = org.Dm.eg.db)
  enrich.go <- enrichGO(gene = genes$ENTREZID, #基因列表文件中的基因名称
                          OrgDb = org.Dm.eg.db,
                          keyType = 'ENTREZID',
                          ont = 'ALL', #可选 BP、MF、CC,也可以指定 ALL 同时计算 3 者
                          pAdjustMethod = 'fdr',
                          pvalueCutoff = 0.05, 
                          qvalueCutoff = 0.2, 
                          readable = TRUE)
  
  GO_plot <- dotplot(enrich.go,title = paste(cl,"GO"),showCategory = 15) + theme_classic() + theme(text = element_text(colour = 'black', size=12))
  ggsave(filename = paste0("./ctrl_only/GO",cl,"_GO.svg"), device = svg, height = 8, width = 10, plot = GO_plot)
}
# barplot(enrich.go,showCategory = 15) + theme_classic()
# cnetplot(enrich.go)

cellchat

Return:

act_weight chord_plot1 chord_plot2 pathway_heatmap pathway_chord act_bubble1 act_bubble2

cellchatobj <- readRDS("cellchatobj.rds")
groupSize <- as.numeric(table(cellchatobj@idents))
# par(mfrow = c(1,2), xpd=TRUE)
#netVisual_circle(cellchatobj@net$count, vertex.weight = groupSize, weight.scale = T, label.edge= F, title.name = "Number of interactions")
act_weight <- netVisual_circle(cellchatobj@net$weight, vertex.weight = groupSize, weight.scale = T, label.edge= F, title.name = "Interaction weights/strength",margin = 0.2)

#chord plot
# par(mfrow = c(1,2), xpd=TRUE)
chord_plot1 <- netVisual_chord_gene(cellchatobj, sources.use = c(6), targets.use = c(1:7), lab.cex = 1, legend.pos.y = 30, legend.pos.x = 10)
chord_plot2 <- netVisual_chord_gene(cellchatobj, sources.use = c(1:7), targets.use = c(6), lab.cex = 1,legend.pos.y = 30, legend.pos.x = 10)


pathways.show <- c("HEDGEHOG signaling pathway") 
# Hierarchy plot

vertex.receiver = seq(1,5) # a numeric vector. 
# netVisual_aggregate(cellchatobj, signaling = pathways.show, layout = "hierarchy",vertex.receiver = vertex.receiver)
# netVisual_aggregate(cellchatobj, signaling = pathways.show, layout = "circle")
pathway_chord <- netVisual_aggregate(cellchatobj, signaling = pathways.show, layout = "chord")


pathways.show <- c("NOTCH signaling pathway") 
par(mfrow=c(1,1))
pathway_heatmap <- netVisual_heatmap(cellchatobj, signaling = pathways.show, color.heatmap = c("#1E90FF","#ff2121")) 
#cellchatobj@netP 对这里的元素画图
pathway_heatmap
for(i in c(1:7)){
act_bubble1 <- netVisual_bubble(cellchatobj, sources.use = i, targets.use = c(1:7), remove.isolate = FALSE, grid.on = TRUE)+ theme_classic() + geom_point(size = 2) +
  theme(text = element_text(family = NULL, colour = 'black', size=10)) #6 PC作为source
act_bubble2 <- netVisual_bubble(cellchatobj, sources.use = c(1:7), targets.use = i, remove.isolate = FALSE, grid.on = TRUE) + theme_classic() + geom_point(size = 2) + 
  theme(text = element_text(family = NULL, colour = 'black', size=10)) #PC作为target
png(filename = paste0(cellchatobj@idents[i],".png"),width = 3500, height = 1800, res = 500)
print(act_bubble1)
dev.off()
png(filename = paste0(cellchatobj@idents[i],"2.png"),width = 3500, height = 1800, res = 500)
print(act_bubble2)
dev.off()
}

组合图片

fig.1left <- plot_grid(umap_plot, markers_heatmap, labels = "AUTO", ncol = 1, nrow = 2, 
                   label_size = 18, rel_heights = c(1, 1), rel_widths = c(1, 1), align = "v")
fig.1 <- plot_grid(fig.1left, dotplot, labels = c("","C"), ncol = 2, nrow = 1, 
                   label_size = 18, rel_heights = c(1, 1),rel_widths = c(1.1, 0.8), align = "v") + theme_void()
ggsave(filename = paste0("fig1r",".png"), device = png, height = 10, width = 16, plot = fig.1)



fig.2 <- mulit_featureplot
ggsave(filename = paste0("fig2",".png"), device = png, height = 10, width = 12, plot = fig.2)


fig.3 <- plot_grid(act_weight, pathway_chord, act_bubble1, act_bubble2, labels = "AUTO", ncol = 2, nrow =2, 
                   label_size = 18,align = "hv" )
ggsave(filename = paste0("fig3",".png"), device = png, height = 10, width = 16, plot = fig.3)

fig.4 <- plot_grid(corheatmap$gtable, labels = "AUTO", label_size = 18, align = "hv" ) + theme_classic() + theme(axis.line = element_blank(), axis.text = element_blank(), axis.ticks = element_blank(), axis.title = element_blank())
ggsave(filename = paste0("fig4",".png"), device = png, height = 8, width = 8, plot = fig.4)


fig.5upper <-  plot_grid(subumap_plot, DBsubumap, labels = c("A","B"), label_size = 18, ncol = 2, nrow = 1)
fig.5 <- plot_grid(fig.5upper, DB_features, labels = c("",""), rel_widths = c(1, 1), label_size = 18, ncol = 1, nrow = 2)
ggsave(filename = paste0("fig5",".png"), device = png, height = 10, width = 10, plot = fig.5)

fig.6 <-  plot_grid(pseudotime_bins$gtable, pseudotime_ridges, pseudotime_ridges2, labels = "AUTO", ncol = 1, nrow = 3, 
                   label_size = 18) + theme_classic() + theme(axis.line = element_blank(), axis.text = element_blank(), axis.ticks = element_blank(), axis.title = element_blank())
ggsave(filename = paste0("fig6",".png"), device = png, height = 18, width = 10, plot = fig.6)

HSD

umap

umap_plot <- umapplot(HSD, group.by = "celltype")
Scale for 'colour' is already present. Adding another scale for 'colour', which will
replace the existing scale.
umap_plot
ggsave(filename = "./HSD_only/HSD_umap.png", 
       device = png, height = 6, width = 7, plot = umap_plot)

markers overview

Return:

markers_heatmap

HSD.markers <- FindAllMarkers(HSD, min.pct = 0.1, 
                                    logfc.threshold = 0.5, only.pos = T)
top5markers <- HSD.markers %>% group_by(cluster) %>% slice_max(n = 5, order_by = avg_logFC)
markers_heatmap <- dhm(top5markers$gene, HSD)
(markers_heatmap + theme(axis.text = element_text(size= 14, color = "black")))%>%
  ggsave(filename = "./HSD_only/HSD_markergene.png", device = png, height = 9, width = 16, plot = .) 

dotplot

top3markers <- HSD.markers %>% group_by(cluster) %>% slice_max(n = 3, order_by = avg_logFC)
## dotplot <- DotPlot(HSD, features = top3markers$gene, cols = c("lightgrey","##ff2121")) + coord_flip() + RotatedAxis() + theme_classic() ##用来获得白色 而不是透明的背景

dotplot <- Dotplot(top3markers$gene[!duplicated(top3markers$gene)], HSD) + coord_flip()

##两个基因umap共定位 #### Return: doublegene_featureplot

gene_name <- c("Tom","peb")
p <- doublegene_featureplot(gene_name, HSD)
ggsave(filename = paste0('./HSD_only/',gene_name[1],"vs",gene_name[2],".png"), device = png, height = 5, width = 20, plot = p)

多基因堆叠小提琴图

Return:

violin_plot

violin_plot(c("salm","kni","Dl","ct","wg","vn","bs"),HSD) %>%
  ggsave(filename = paste0("./HSD_only/HSD_violinplot.png"), device = png, height = 5, width = 5, plot = .)

多图featureplot

Return:

mulit_featureplot

gene_name <- c("bnl", "btl", "htl", "Egfr") ##可视化的基因名称
multi_featureplot(gene_name, HSD) %>% ggsave(paste0("./HSD_only/",as.character(gene_name), ".png"),device = png, width = 6, height = 5, plot = .)

multi_featureplot(c("upd2","dome","PlexA","PlexB"), HSD) %>% ggsave("./HSD_only/upd2dome.png",device = png,height = 6, width = 7, plot = .)

multi_featureplot(c("Sema5c","Sema1a","Sema2a","Sema1b"), HSD)%>% ggsave("./HSD_only/sema.png",device = png,height = 6, width = 7, plot = .)

multi_featureplot(c("peb","Dad","dpp","ex"),HSD) %>% ggsave("./HSD_only/pebDadex.png",device = png,height = 6, width = 7, plot = .)

转录因子 SCENIC

Return:

TFheatmap

regulonActivity <- read.csv("./regulonActivity.csv",row.names = 1)
topTFs <- read.csv("./topRegulators.csv")
top5 <- topTFs %>% group_by(seuratCluster) %>% slice_max(n = 5, order_by = RelativeActivity)

##根据已知的top5更新行顺序
regulonActivity <- regulonActivity[sapply(top5$Regulon, function(e) {which(rownames(regulonActivity) == e)}), ]
##annotation_col <-  data.frame(cluster = factor(top5$seuratCluster), row.names = make.names(top5$Regulon,TRUE)) ##make.names用来生成不冲突的行
regulonActivity <- regulonActivity[,c("DB","DT","NE","PC","SB","TC","VB")]

TFheatmap <- pheatmap(regulonActivity, breaks = unique(c(seq(-3,3, length=400))), 
                 color = colorRampPalette(c("##1E90FF", "white", "##ff2121"))(400),
                border_color = NA, cluster_rows = FALSE, cluster_cols = FALSE,
                main = "regulonActivity",angle_col = 45, show_rownames = T)
##ggsave(filename = paste0("regulonActivity",".svg"), device = svg, height = 8, width = 12, plot = TFheatmap)

GO

Return:

GO_plot

library(org.Dm.eg.db)
for (cl in levels(Idents(HSD))){
  ##选择cluster对应的marker
  gene_list <- HSD.markers[HSD.markers$cluster==cl,]$gene
  ##ID转换
  genes <- bitr(gene_list, fromType="SYMBOL",toType=c("ENTREZID","ENSEMBL"),
                   OrgDb = org.Dm.eg.db)
  enrich.go <- enrichGO(gene = genes$ENTREZID, ##基因列表文件中的基因名称
                          OrgDb = org.Dm.eg.db,
                          keyType = 'ENTREZID',
                          ont = 'ALL', ##可选 BP、MF、CC,也可以指定 ALL 同时计算 3 者
                          pAdjustMethod = 'fdr',
                          pvalueCutoff = 0.05, 
                          qvalueCutoff = 0.2, 
                          readable = TRUE)
  
  GO_plot <- dotplot(enrich.go,title = paste(cl,"GO"),showCategory = 15) + theme_classic() + theme(text = element_text(colour = 'black', size=12))
  ggsave(filename = paste0(cl,"_GO.svg"), device = svg, height = 8, width = 10, plot = GO_plot)
}
## barplot(enrich.go,showCategory = 15) + theme_classic()
## cnetplot(enrich.go)

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).

The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyDlj6rliIbmnpBjdHJsCmBgYHtyfQpzb3VyY2UoInRpYW5mZW5nUndyYXBwZXJzLlIiKQpgYGAKCiMgQ3RybAojIyB1bWFwCiMjIyBSZXR1cm46IAp1bWFwX3Bsb3QKYGBge3IgdW1hcCwgaW5jbHVkZT1GQUxTRX0KdW1hcF9wbG90IDwtIHVtYXBwbG90KGN0cmwpCnVtYXBfcGxvdApnZ3NhdmUoZmlsZW5hbWUgPSAiLi9jdHJsX29ubHkvY3RybF91bWFwLnBuZyIsIGRldmljZSA9IHBuZywgaGVpZ2h0ID0gNiwgd2lkdGggPSA3LCBwbG90ID0gdW1hcF9wbG90KQoKdW1hcF9wbG90IDwtIHVtYXBwbG90KGN0cmwsIGdyb3VwLmJ5ID0gImNlbGx0eXBlIikKdW1hcF9wbG90Cmdnc2F2ZShmaWxlbmFtZSA9ICJjdHJsX3VtYXAucG5nIiwgCiAgICAgICBkZXZpY2UgPSBwbmcsIGhlaWdodCA9IDYsIHdpZHRoID0gNywgcGxvdCA9IHVtYXBfcGxvdCkKCmBgYAoKIyMgbWFya2VycyBvdmVydmlldwojIyMgUmV0dXJuOgptYXJrZXJzX2hlYXRtYXAKYGBge3IgLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xNX0KY3RybC5tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKGN0cmwsIG1pbi5wY3QgPSAwLjEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dmYy50aHJlc2hvbGQgPSAwLjUsIG9ubHkucG9zID0gVCkKdG9wNW1hcmtlcnMgPC0gY3RybC5tYXJrZXJzICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgc2xpY2VfbWF4KG4gPSA1LCBvcmRlcl9ieSA9IGF2Z19sb2dGQykKbWFya2Vyc19oZWF0bWFwIDwtIGRobSh0b3A1bWFya2VycyRnZW5lLCBjdHJsKQoobWFya2Vyc19oZWF0bWFwICsgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9IDE0LCBjb2xvciA9ICJibGFjayIpKSklPiUKICBnZ3NhdmUoZmlsZW5hbWUgPSAiLi9jdHJsX29ubHkvY3RybF9tYXJrZXJnZW5lLnBuZyIsIGRldmljZSA9IHBuZywgaGVpZ2h0ID0gOSwgd2lkdGggPSAxNiwgcGxvdCA9IC4pIApgYGAKCgojIyBkb3RwbG90CmBgYHtyIGRvdHBsb3R9CnRvcDNtYXJrZXJzIDwtIGN0cmwubWFya2VycyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHNsaWNlX21heChuID0gMywgb3JkZXJfYnkgPSBhdmdfbG9nRkMpCiMgZG90cGxvdCA8LSBEb3RQbG90KGN0cmwsIGZlYXR1cmVzID0gdG9wM21hcmtlcnMkZ2VuZSwgY29scyA9IGMoImxpZ2h0Z3JleSIsIiNmZjIxMjEiKSkgKyBjb29yZF9mbGlwKCkgKyBSb3RhdGVkQXhpcygpICsgdGhlbWVfY2xhc3NpYygpICPnlKjmnaXojrflvpfnmb3oibIg6ICM5LiN5piv6YCP5piO55qE6IOM5pmvCgpkb3RwbG90IDwtIERvdHBsb3QodG9wM21hcmtlcnMkZ2VuZVshZHVwbGljYXRlZCh0b3AzbWFya2VycyRnZW5lKV0sIGN0cmwpICsgY29vcmRfZmxpcCgpCgpgYGAKCiMj5Y2V5Liq5Z+65ZugZmVhdHVyZXBsb3QKIyMjIFJldHVybjoKZ2VuZV9wbG90CmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xNX0KZ2VuZV9wbG90IDwtIGYoIkdhc3AiLGN0cmwpCiNnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZTAoZ2VuZV9uYW1lLCIuc3ZnIiksIGRldmljZSA9IHN2ZywgaGVpZ2h0ID0gNSwgd2lkdGggPSA2LCBwbG90ID0gZ2VuZV9wbG90KSAj5a+5c3Zn6LCD5pW05Z2Q5qCH6L20CmBgYAoKCiMj5Lik5Liq5Z+65ZugdW1hcOWFseWumuS9jSAKIyMjIFJldHVybjoKZG91YmxlZ2VuZV9mZWF0dXJlcGxvdApgYGB7ciBtYXJrZXJzLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xNX0KZ2VuZV9uYW1lIDwtIGMoIlRvbSIsInBlYiIpCnAgPC0gZG91YmxlZ2VuZV9mZWF0dXJlcGxvdChnZW5lX25hbWUsIGN0cmwpCmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMChnZW5lX25hbWVbMV0sInZzIixnZW5lX25hbWVbMl0sIi5wbmciKSwgZGV2aWNlID0gcG5nLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDIwLCBwbG90ID0gcCkgI+WvuXN2Z+iwg+aVtOWdkOagh+i9tApgYGAKCiMg5aSa5Z+65Zug5aCG5Y+g5bCP5o+Q55C05Zu+IAojIyBSZXR1cm46CnZpb2xpbl9wbG90CmBgYHtyLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD00fQp2aW9saW5fcGxvdChjKCJzYWxtIiwia25pIiwiRGwiLCJjdCIsIndnIiwidm4iLCJicyIpLGN0cmwpICU+JQogIGdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMCgidmlvbGlucGxvdC5wbmciKSwgZGV2aWNlID0gcG5nLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDUsIHBsb3QgPSAuKQpgYGAKCiMjIOWkmuWbvmZlYXR1cmVwbG90CiMjIyBSZXR1cm46Cm11bGl0X2ZlYXR1cmVwbG90CmBgYHtyIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CmdlbmVfbmFtZSA8LSBjKCJibmwiLCAiYnRsIiwgImh0bCIsICJFZ2ZyIikgI+WPr+inhuWMlueahOWfuuWboOWQjeensAptdWx0aV9mZWF0dXJlcGxvdChnZW5lX25hbWUsIGN0cmwpICU+JSBnZ3NhdmUocGFzdGUwKCIuL2N0cmxfb25seS8iLGFzLmNoYXJhY3RlcihnZW5lX25hbWUpLCAiLnBuZyIpLGRldmljZSA9IHBuZywgd2lkdGggPSA2LCBoZWlnaHQgPSA1LCBwbG90ID0gLikKCm11bHRpX2ZlYXR1cmVwbG90KGMoInVwZDIiLCJkb21lIiwiUGxleEEiLCJQbGV4QiIpLCBjdHJsKSAlPiUgZ2dzYXZlKCIuL2N0cmxfb25seS91cGQyZG9tZS5wbmciLGRldmljZSA9IHBuZyxoZWlnaHQgPSA2LCB3aWR0aCA9IDcsIHBsb3QgPSAuKQoKbXVsdGlfZmVhdHVyZXBsb3QoYygiU2VtYTVjIiwiU2VtYTFhIiwiU2VtYTJhIiwiU2VtYTFiIiksIGN0cmwpJT4lIGdnc2F2ZSgiLi9jdHJsX29ubHkvc2VtYS5wbmciLGRldmljZSA9IHBuZyxoZWlnaHQgPSA2LCB3aWR0aCA9IDcsIHBsb3QgPSAuKQoKbXVsdGlfZmVhdHVyZXBsb3QoYygicGViIiwiRGFkIiwiZHBwIiwiZXgiKSxjdHJsKSAlPiUgZ2dzYXZlKCIuL2N0cmxfb25seS9wZWJEYWRleC5wbmciLGRldmljZSA9IHBuZyxoZWlnaHQgPSA2LCB3aWR0aCA9IDcsIHBsb3QgPSAuKQpgYGAKCgojIyDovazlvZXlm6DlrZAgU0NFTklDCiMjIyBSZXR1cm46ClRGaGVhdG1hcApgYGB7cn0KcmVndWxvbkFjdGl2aXR5IDwtIHJlYWQuY3N2KCIuL3JlZ3Vsb25BY3Rpdml0eS5jc3YiLHJvdy5uYW1lcyA9IDEpCnRvcFRGcyA8LSByZWFkLmNzdigiLi90b3BSZWd1bGF0b3JzLmNzdiIpCnRvcDUgPC0gdG9wVEZzICU+JSBncm91cF9ieShzZXVyYXRDbHVzdGVyKSAlPiUgc2xpY2VfbWF4KG4gPSA1LCBvcmRlcl9ieSA9IFJlbGF0aXZlQWN0aXZpdHkpCgoj5qC55o2u5bey55+l55qEdG9wNeabtOaWsOihjOmhuuW6jwpyZWd1bG9uQWN0aXZpdHkgPC0gcmVndWxvbkFjdGl2aXR5W3NhcHBseSh0b3A1JFJlZ3Vsb24sIGZ1bmN0aW9uKGUpIHt3aGljaChyb3duYW1lcyhyZWd1bG9uQWN0aXZpdHkpID09IGUpfSksIF0KI2Fubm90YXRpb25fY29sIDwtICBkYXRhLmZyYW1lKGNsdXN0ZXIgPSBmYWN0b3IodG9wNSRzZXVyYXRDbHVzdGVyKSwgcm93Lm5hbWVzID0gbWFrZS5uYW1lcyh0b3A1JFJlZ3Vsb24sVFJVRSkpICNtYWtlLm5hbWVz55So5p2l55Sf5oiQ5LiN5Yay56qB55qE6KGMCnJlZ3Vsb25BY3Rpdml0eSA8LSByZWd1bG9uQWN0aXZpdHlbLGMoIkRCIiwiRFQiLCJORSIsIlBDIiwiU0IiLCJUQyIsIlZCIildCgpURmhlYXRtYXAgPC0gcGhlYXRtYXAocmVndWxvbkFjdGl2aXR5LCBicmVha3MgPSB1bmlxdWUoYyhzZXEoLTMsMywgbGVuZ3RoPTQwMCkpKSwgCiAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xvclJhbXBQYWxldHRlKGMoIiMxRTkwRkYiLCAid2hpdGUiLCAiI2ZmMjEyMSIpKSg0MDApLAogICAgICAgICAgICAgICAgYm9yZGVyX2NvbG9yID0gTkEsIGNsdXN0ZXJfcm93cyA9IEZBTFNFLCBjbHVzdGVyX2NvbHMgPSBGQUxTRSwKICAgICAgICAgICAgICAgIG1haW4gPSAicmVndWxvbkFjdGl2aXR5IixhbmdsZV9jb2wgPSA0NSwgc2hvd19yb3duYW1lcyA9IFQpCiNnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZTAoInJlZ3Vsb25BY3Rpdml0eSIsIi5zdmciKSwgZGV2aWNlID0gc3ZnLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDEyLCBwbG90ID0gVEZoZWF0bWFwKQpgYGAKCiMjIHBzZXVkb3RpbWUgZmVhdHVyZXBsb3QKIyMjIFJldHVybjoKcHNldWRvdGltZSBpbiBmZWF0dXJlUGxvdApgYGB7cn0KcHNldWRvdGltZVBsb3QgPC0gZigicHNldWRvdGltZSIsIGNvbHMgPSBjKCJob3RwaW5rIiwiIzFFOTBGRiIpKQojZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKCJwdF9mZWF0dXJlcGxvdDIiLCIuc3ZnIiksIGRldmljZSA9IHN2ZywgaGVpZ2h0ID0gNSwgd2lkdGggPSA2LCBwbG90ID0gcHNldWRvdGltZVBsb3QpCmBgYAoKIyMg5Z+65ZugK+aLn+aXtgojIyMgUmV0dXJuOgpnZW5ld2l0aHBzZXVkb3RpbWUKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MjB9CmRhdE1hdCA8LSBhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGN0cmwsc2xvdCA9ICJkYXRhIikpCmRmIDwtIGRhdGEuZnJhbWUodChjdHJsJHBzZXVkb3RpbWUpKQpkZiA8LSBkby5jYWxsKGRhdGEuZnJhbWUsbGFwcGx5KGRmLCBmdW5jdGlvbih4KXsKICB4ID0geC8yMAogIHJlcGxhY2UoeCwgaXMuaW5maW5pdGUoeCksMCl9KSkKcm93bmFtZXMoZGYpIDwtICJwc2V1ZG90aW1lIgpjb2xuYW1lcyhkZikgPC0gY29sbmFtZXMoZGF0TWF0KQpkYXRNYXQgPC0gcmJpbmQoZGYsIGRhdE1hdCkKCnRlc3QgPC0gQ3JlYXRlU2V1cmF0T2JqZWN0KGNvdW50cyA9IGRhdE1hdCkKdGVzdEByZWR1Y3Rpb25zW1sidW1hcCJdXSA8LSBjdHJsQHJlZHVjdGlvbnNbWyJ1bWFwIl1dCnRlc3RAYWN0aXZlLmlkZW50IDwtIGN0cmxAYWN0aXZlLmlkZW50CiMgU2V0QXNzYXlEYXRhKGN0cmwsc2xvdCA9ICJkYXRhIiwgbmV3LmRhdGEgPSBkYXRNYXQpCiPlhbHlrprkvY0KZ2VuZV9uYW1lIDwtIGMoIlRvbSIsInBzZXVkb3RpbWUiKQpnZW5ld2l0aHBzZXVkb3RpbWUgPC0gRmVhdHVyZVBsb3QodGVzdCwgcHQuc2l6ZSA9IDAuOCwgc2xvdCA9ICJjb3VudHMiLG1pbi5jdXRvZmYgPSAwLCBtYXguY3V0b2ZmID0gNCwgZmVhdHVyZXMgPSBnZW5lX25hbWUsIGNvbHMgPSBjKCJsaWdodGdyZXkiLCIjMUU5MEZGIiwgIiNmZjIxMjEiKSwgbGFiZWwgPSBUUlVFLCBibGVuZCA9IFQsIGJsZW5kLnRocmVzaG9sZCA9IDApICsgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCiNnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZTAoZ2VuZV9uYW1lWzFdLCJ2cyIsZ2VuZV9uYW1lWzJdLCIucG5nIiksIGRldmljZSA9IHBuZywgaGVpZ2h0ID0gNSwgd2lkdGggPSAyMCwgcGxvdCA9IGdlbmV3aXRocHNldWRvdGltZSkKYGBgCgojIyDln7rlm6Dmi5/ml7booajovr4KIyMjIFJldHVybjoKcHNldWRvdGltZV9jZWxscyAgICBwc2V1ZG90aW1lX2JpbnMgICBwc2V1ZG90aW1lX3JpZGdlcyAgIHBzZXVkb3RpbWVfcmlkZ2VzMgpgYGB7ciBQc2V1ZG90aW1lQW5hbHlzaXMsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9CiPpgInlj5bnu4bog57kuprnvqTov5vooYzliIbmnpAKY2VsbC5zdWJzZXQgPC0gc3Vic2V0KHggPSBjdHJsLGlkZW50cyA9IGMoIkRUIiwiU0IiKSxpbnZlcnQgPSBGQUxTRSApCm5iaW5zIDwtICAxNQpjZWxsLnN1YnNldCA8LSBtYWtlX2JpbnMoY2VsbC5zdWJzZXQsbmJpbnMpCnRvcF9zcGVjaWZpY19tYXJrZXJfaWRzIDwtIHJlYWRSRFMoInRvcF9zcGVjaWZpY19tYXJrZXJfaWRzLlJEUyIpCnBzZXVkb3RpbWVfY2VsbHMgPC0gbWFrZV9wc2V1ZG90aW1lX2hlYXRtYXBfYnljZWxscyhjZWxsLnN1YnNldCx0b3Bfc3BlY2lmaWNfbWFya2VyX2lkcyw1MCkKI2dnc2F2ZShmaWxlbmFtZSA9ICJwc2V1ZG90aW1lX2hlYXRtYXBfYnljZWxscy5wbmciLCBkZXZpY2UgPSBwbmcsIGhlaWdodCA9IDYsIHdpZHRoID0gMTAsIHBsb3QgPSBwc2V1ZG90aW1lX2NlbGxzKQoKcHNldWRvdGltZV9iaW5zIDwtIG1ha2VfcHNldWRvdGltZV9oZWF0bWFwX2F2ZXJhZ2UoY2VsbC5zdWJzZXQsdG9wX3NwZWNpZmljX21hcmtlcl9pZHMsNTApCiNnZ3NhdmUoZmlsZW5hbWUgPSAicHNldWRvdGltZV9oZWF0bWFwX2JpbnMucG5nIiwgZGV2aWNlID0gcG5nLCBoZWlnaHQgPSA2LCB3aWR0aCA9IDEwLCBwbG90ID0gcHNldWRvdGltZV9iaW5zKQoKZGYgPC0gZ2V0X2RyYXcoY3RybCwgZ2VuZWxpc3QgPSBoZWFkKHRvcF9zcGVjaWZpY19tYXJrZXJfaWRzLDEwKSwgZXhwcl90aHJlc2hvbGQgPSAxKQoKcHNldWRvdGltZV9yaWRnZXMgPC0gZ2dwbG90KGRmLCBhZXMoeCA9IHBzZXVkb3RpbWUgLCB5ID0gZ2VuZSAsIGZpbGwgPSBnZW5lKSkgKwogZ2dyaWRnZXM6Omdlb21fZGVuc2l0eV9yaWRnZXMoYWxwaGEgPSAwLjUsc2hvdy5sZWdlbmQgPVQpICsgbGFicyh0aXRsZSA9ICdERUdzIHdpdGggcHNldWRvdGltZScpKwogdGhlbWVfaXBzdW0oKSArICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiLCBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjEsICJsaW5lcyIpLAogICAgICAgICAgICAgICAgICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKQojZ2dzYXZlKGZpbGVuYW1lID0gInBzZXVkb3RpbWVfcmlkZ2VzLnBuZyIsIGRldmljZSA9IHBuZywgaGVpZ2h0ID0gOCwgd2lkdGggPSAxMCwgcGxvdCA9IHBzZXVkb3RpbWVfcmlkZ2VzKQoKcHNldWRvdGltZV9yaWRnZXMyIDwtIGdncGxvdChkZiwgYWVzKHggPSBwc2V1ZG90aW1lLCB5ID0gZ2VuZSwgZmlsbCA9IC4ueC4uKSkgICsKICBnZW9tX2RlbnNpdHlfcmlkZ2VzX2dyYWRpZW50KHNjYWxlID0gMywgcmVsX21pbl9oZWlnaHQgPSAwLjAxLGFscGhhID0gMC41KSArCiAgc2NhbGVfZmlsbF92aXJpZGlzKG5hbWUgPSBjdHJsJHBzZXVkb3RpbWUsIG9wdGlvbiA9ICJDIikgKwogIGxhYnModGl0bGUgPSAnREVHcyB3aXRoIHBzZXVkb3RpbWUnKSArIHRoZW1lX2lwc3VtKCkgKwogICAgdGhlbWUoCiAgICAgIGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsCiAgICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuMSwgImxpbmVzIiksCiAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpCiMjZ2dzYXZlKGZpbGVuYW1lID0gInBzZXVkb3RpbWVfcmlkZ2VzMi5qcGciLCBkZXZpY2UgPSBqcGVnLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDEwLCBwbG90ID0gcHNldWRvdGltZV9yaWRnZXMyKQoKYGBgCgojIyBHTwojIyMgUmV0dXJuOgpHT19wbG90CmBgYHtyIEdPfQpsaWJyYXJ5KG9yZy5EbS5lZy5kYikKZm9yIChjbCBpbiBsZXZlbHMoSWRlbnRzKGN0cmwpKSl7CiAgI+mAieaLqWNsdXN0ZXLlr7nlupTnmoRtYXJrZXIKICBnZW5lX2xpc3QgPC0gY3RybC5tYXJrZXJzW2N0cmwubWFya2VycyRjbHVzdGVyPT1jbCxdJGdlbmUKICAjSUTovazmjaIKICBnZW5lcyA8LSBiaXRyKGdlbmVfbGlzdCwgZnJvbVR5cGU9IlNZTUJPTCIsdG9UeXBlPWMoIkVOVFJFWklEIiwiRU5TRU1CTCIpLAogICAgICAgICAgICAgICAgICAgT3JnRGIgPSBvcmcuRG0uZWcuZGIpCiAgZW5yaWNoLmdvIDwtIGVucmljaEdPKGdlbmUgPSBnZW5lcyRFTlRSRVpJRCwgI+WfuuWboOWIl+ihqOaWh+S7tuS4reeahOWfuuWboOWQjeensAogICAgICAgICAgICAgICAgICAgICAgICAgIE9yZ0RiID0gb3JnLkRtLmVnLmRiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGtleVR5cGUgPSAnRU5UUkVaSUQnLAogICAgICAgICAgICAgICAgICAgICAgICAgIG9udCA9ICdBTEwnLCAj5Y+v6YCJIEJQ44CBTUbjgIFDQ++8jOS5n+WPr+S7peaMh+WumiBBTEwg5ZCM5pe26K6h566XIDMg6ICFCiAgICAgICAgICAgICAgICAgICAgICAgICAgcEFkanVzdE1ldGhvZCA9ICdmZHInLAogICAgICAgICAgICAgICAgICAgICAgICAgIHB2YWx1ZUN1dG9mZiA9IDAuMDUsIAogICAgICAgICAgICAgICAgICAgICAgICAgIHF2YWx1ZUN1dG9mZiA9IDAuMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgcmVhZGFibGUgPSBUUlVFKQogIAogIEdPX3Bsb3QgPC0gZG90cGxvdChlbnJpY2guZ28sdGl0bGUgPSBwYXN0ZShjbCwiR08iKSxzaG93Q2F0ZWdvcnkgPSAxNSkgKyB0aGVtZV9jbGFzc2ljKCkgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICdibGFjaycsIHNpemU9MTIpKQogIGdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMCgiLi9jdHJsX29ubHkvR08iLGNsLCJfR08uc3ZnIiksIGRldmljZSA9IHN2ZywgaGVpZ2h0ID0gOCwgd2lkdGggPSAxMCwgcGxvdCA9IEdPX3Bsb3QpCn0KIyBiYXJwbG90KGVucmljaC5nbyxzaG93Q2F0ZWdvcnkgPSAxNSkgKyB0aGVtZV9jbGFzc2ljKCkKIyBjbmV0cGxvdChlbnJpY2guZ28pCgpgYGAKCiMjIGNlbGxjaGF0CiMjIyBSZXR1cm46IAphY3Rfd2VpZ2h0CmNob3JkX3Bsb3QxICAgY2hvcmRfcGxvdDIKcGF0aHdheV9oZWF0bWFwICAgcGF0aHdheV9jaG9yZCAKYWN0X2J1YmJsZTEgICBhY3RfYnViYmxlMgpgYGB7ciBjZWxsY2hhdH0KY2VsbGNoYXRvYmogPC0gcmVhZFJEUygiY2VsbGNoYXRvYmoucmRzIikKZ3JvdXBTaXplIDwtIGFzLm51bWVyaWModGFibGUoY2VsbGNoYXRvYmpAaWRlbnRzKSkKIyBwYXIobWZyb3cgPSBjKDEsMiksIHhwZD1UUlVFKQojbmV0VmlzdWFsX2NpcmNsZShjZWxsY2hhdG9iakBuZXQkY291bnQsIHZlcnRleC53ZWlnaHQgPSBncm91cFNpemUsIHdlaWdodC5zY2FsZSA9IFQsIGxhYmVsLmVkZ2U9IEYsIHRpdGxlLm5hbWUgPSAiTnVtYmVyIG9mIGludGVyYWN0aW9ucyIpCmFjdF93ZWlnaHQgPC0gbmV0VmlzdWFsX2NpcmNsZShjZWxsY2hhdG9iakBuZXQkd2VpZ2h0LCB2ZXJ0ZXgud2VpZ2h0ID0gZ3JvdXBTaXplLCB3ZWlnaHQuc2NhbGUgPSBULCBsYWJlbC5lZGdlPSBGLCB0aXRsZS5uYW1lID0gIkludGVyYWN0aW9uIHdlaWdodHMvc3RyZW5ndGgiLG1hcmdpbiA9IDAuMikKCiNjaG9yZCBwbG90CiMgcGFyKG1mcm93ID0gYygxLDIpLCB4cGQ9VFJVRSkKY2hvcmRfcGxvdDEgPC0gbmV0VmlzdWFsX2Nob3JkX2dlbmUoY2VsbGNoYXRvYmosIHNvdXJjZXMudXNlID0gYyg2KSwgdGFyZ2V0cy51c2UgPSBjKDE6NyksIGxhYi5jZXggPSAxLCBsZWdlbmQucG9zLnkgPSAzMCwgbGVnZW5kLnBvcy54ID0gMTApCmNob3JkX3Bsb3QyIDwtIG5ldFZpc3VhbF9jaG9yZF9nZW5lKGNlbGxjaGF0b2JqLCBzb3VyY2VzLnVzZSA9IGMoMTo3KSwgdGFyZ2V0cy51c2UgPSBjKDYpLCBsYWIuY2V4ID0gMSxsZWdlbmQucG9zLnkgPSAzMCwgbGVnZW5kLnBvcy54ID0gMTApCgoKcGF0aHdheXMuc2hvdyA8LSBjKCJIRURHRUhPRyBzaWduYWxpbmcgcGF0aHdheSIpIAojIEhpZXJhcmNoeSBwbG90Cgp2ZXJ0ZXgucmVjZWl2ZXIgPSBzZXEoMSw1KSAjIGEgbnVtZXJpYyB2ZWN0b3IuIAojIG5ldFZpc3VhbF9hZ2dyZWdhdGUoY2VsbGNoYXRvYmosIHNpZ25hbGluZyA9IHBhdGh3YXlzLnNob3csIGxheW91dCA9ICJoaWVyYXJjaHkiLHZlcnRleC5yZWNlaXZlciA9IHZlcnRleC5yZWNlaXZlcikKIyBuZXRWaXN1YWxfYWdncmVnYXRlKGNlbGxjaGF0b2JqLCBzaWduYWxpbmcgPSBwYXRod2F5cy5zaG93LCBsYXlvdXQgPSAiY2lyY2xlIikKcGF0aHdheV9jaG9yZCA8LSBuZXRWaXN1YWxfYWdncmVnYXRlKGNlbGxjaGF0b2JqLCBzaWduYWxpbmcgPSBwYXRod2F5cy5zaG93LCBsYXlvdXQgPSAiY2hvcmQiKQoKCnBhdGh3YXlzLnNob3cgPC0gYygiTk9UQ0ggc2lnbmFsaW5nIHBhdGh3YXkiKSAKcGFyKG1mcm93PWMoMSwxKSkKcGF0aHdheV9oZWF0bWFwIDwtIG5ldFZpc3VhbF9oZWF0bWFwKGNlbGxjaGF0b2JqLCBzaWduYWxpbmcgPSBwYXRod2F5cy5zaG93LCBjb2xvci5oZWF0bWFwID0gYygiIzFFOTBGRiIsIiNmZjIxMjEiKSkgCiNjZWxsY2hhdG9iakBuZXRQIOWvuei/memHjOeahOWFg+e0oOeUu+WbvgpwYXRod2F5X2hlYXRtYXAKYGBgCgoKYGBge3IgY2VsbGNoYXQgYWN0X2J1YmJsZX0KZm9yKGkgaW4gYygxOjcpKXsKYWN0X2J1YmJsZTEgPC0gbmV0VmlzdWFsX2J1YmJsZShjZWxsY2hhdG9iaiwgc291cmNlcy51c2UgPSBpLCB0YXJnZXRzLnVzZSA9IGMoMTo3KSwgcmVtb3ZlLmlzb2xhdGUgPSBGQUxTRSwgZ3JpZC5vbiA9IFRSVUUpKyB0aGVtZV9jbGFzc2ljKCkgKyBnZW9tX3BvaW50KHNpemUgPSAyKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBOVUxMLCBjb2xvdXIgPSAnYmxhY2snLCBzaXplPTEwKSkgIzYgUEPkvZzkuLpzb3VyY2UKYWN0X2J1YmJsZTIgPC0gbmV0VmlzdWFsX2J1YmJsZShjZWxsY2hhdG9iaiwgc291cmNlcy51c2UgPSBjKDE6NyksIHRhcmdldHMudXNlID0gaSwgcmVtb3ZlLmlzb2xhdGUgPSBGQUxTRSwgZ3JpZC5vbiA9IFRSVUUpICsgdGhlbWVfY2xhc3NpYygpICsgZ2VvbV9wb2ludChzaXplID0gMikgKyAKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IE5VTEwsIGNvbG91ciA9ICdibGFjaycsIHNpemU9MTApKSAjUEPkvZzkuLp0YXJnZXQKcG5nKGZpbGVuYW1lID0gcGFzdGUwKGNlbGxjaGF0b2JqQGlkZW50c1tpXSwiLnBuZyIpLHdpZHRoID0gMzUwMCwgaGVpZ2h0ID0gMTgwMCwgcmVzID0gNTAwKQpwcmludChhY3RfYnViYmxlMSkKZGV2Lm9mZigpCnBuZyhmaWxlbmFtZSA9IHBhc3RlMChjZWxsY2hhdG9iakBpZGVudHNbaV0sIjIucG5nIiksd2lkdGggPSAzNTAwLCBoZWlnaHQgPSAxODAwLCByZXMgPSA1MDApCnByaW50KGFjdF9idWJibGUyKQpkZXYub2ZmKCkKfQpgYGAKCgojIyDnu4TlkIjlm77niYcKYGBge3J9CmZpZy4xbGVmdCA8LSBwbG90X2dyaWQodW1hcF9wbG90LCBtYXJrZXJzX2hlYXRtYXAsIGxhYmVscyA9ICJBVVRPIiwgbmNvbCA9IDEsIG5yb3cgPSAyLCAKICAgICAgICAgICAgICAgICAgIGxhYmVsX3NpemUgPSAxOCwgcmVsX2hlaWdodHMgPSBjKDEsIDEpLCByZWxfd2lkdGhzID0gYygxLCAxKSwgYWxpZ24gPSAidiIpCmZpZy4xIDwtIHBsb3RfZ3JpZChmaWcuMWxlZnQsIGRvdHBsb3QsIGxhYmVscyA9IGMoIiIsIkMiKSwgbmNvbCA9IDIsIG5yb3cgPSAxLCAKICAgICAgICAgICAgICAgICAgIGxhYmVsX3NpemUgPSAxOCwgcmVsX2hlaWdodHMgPSBjKDEsIDEpLHJlbF93aWR0aHMgPSBjKDEuMSwgMC44KSwgYWxpZ24gPSAidiIpICsgdGhlbWVfdm9pZCgpCmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMCgiZmlnMXIiLCIucG5nIiksIGRldmljZSA9IHBuZywgaGVpZ2h0ID0gMTAsIHdpZHRoID0gMTYsIHBsb3QgPSBmaWcuMSkKCgoKZmlnLjIgPC0gbXVsaXRfZmVhdHVyZXBsb3QKZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKCJmaWcyIiwiLnBuZyIpLCBkZXZpY2UgPSBwbmcsIGhlaWdodCA9IDEwLCB3aWR0aCA9IDEyLCBwbG90ID0gZmlnLjIpCgoKZmlnLjMgPC0gcGxvdF9ncmlkKGFjdF93ZWlnaHQsIHBhdGh3YXlfY2hvcmQsIGFjdF9idWJibGUxLCBhY3RfYnViYmxlMiwgbGFiZWxzID0gIkFVVE8iLCBuY29sID0gMiwgbnJvdyA9MiwgCiAgICAgICAgICAgICAgICAgICBsYWJlbF9zaXplID0gMTgsYWxpZ24gPSAiaHYiICkKZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKCJmaWczIiwiLnBuZyIpLCBkZXZpY2UgPSBwbmcsIGhlaWdodCA9IDEwLCB3aWR0aCA9IDE2LCBwbG90ID0gZmlnLjMpCgpmaWcuNCA8LSBwbG90X2dyaWQoY29yaGVhdG1hcCRndGFibGUsIGxhYmVscyA9ICJBVVRPIiwgbGFiZWxfc2l6ZSA9IDE4LCBhbGlnbiA9ICJodiIgKSArIHRoZW1lX2NsYXNzaWMoKSArIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZTAoImZpZzQiLCIucG5nIiksIGRldmljZSA9IHBuZywgaGVpZ2h0ID0gOCwgd2lkdGggPSA4LCBwbG90ID0gZmlnLjQpCgoKZmlnLjV1cHBlciA8LSAgcGxvdF9ncmlkKHN1YnVtYXBfcGxvdCwgREJzdWJ1bWFwLCBsYWJlbHMgPSBjKCJBIiwiQiIpLCBsYWJlbF9zaXplID0gMTgsIG5jb2wgPSAyLCBucm93ID0gMSkKZmlnLjUgPC0gcGxvdF9ncmlkKGZpZy41dXBwZXIsIERCX2ZlYXR1cmVzLCBsYWJlbHMgPSBjKCIiLCIiKSwgcmVsX3dpZHRocyA9IGMoMSwgMSksIGxhYmVsX3NpemUgPSAxOCwgbmNvbCA9IDEsIG5yb3cgPSAyKQpnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZTAoImZpZzUiLCIucG5nIiksIGRldmljZSA9IHBuZywgaGVpZ2h0ID0gMTAsIHdpZHRoID0gMTAsIHBsb3QgPSBmaWcuNSkKCmZpZy42IDwtICBwbG90X2dyaWQocHNldWRvdGltZV9iaW5zJGd0YWJsZSwgcHNldWRvdGltZV9yaWRnZXMsIHBzZXVkb3RpbWVfcmlkZ2VzMiwgbGFiZWxzID0gIkFVVE8iLCBuY29sID0gMSwgbnJvdyA9IDMsIAogICAgICAgICAgICAgICAgICAgbGFiZWxfc2l6ZSA9IDE4KSArIHRoZW1lX2NsYXNzaWMoKSArIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZTAoImZpZzYiLCIucG5nIiksIGRldmljZSA9IHBuZywgaGVpZ2h0ID0gMTgsIHdpZHRoID0gMTAsIHBsb3QgPSBmaWcuNikKYGBgCgoKIyBIU0QKIyMgdW1hcAoKYGBge3J9CnVtYXBfcGxvdCA8LSB1bWFwcGxvdChIU0QsIGdyb3VwLmJ5ID0gImNlbGx0eXBlIikKdW1hcF9wbG90Cmdnc2F2ZShmaWxlbmFtZSA9ICIuL0hTRF9vbmx5L0hTRF91bWFwLnBuZyIsIAogICAgICAgZGV2aWNlID0gcG5nLCBoZWlnaHQgPSA2LCB3aWR0aCA9IDcsIHBsb3QgPSB1bWFwX3Bsb3QpCgpgYGAKCiMjIG1hcmtlcnMgb3ZlcnZpZXcKIyMjIFJldHVybjoKbWFya2Vyc19oZWF0bWFwCmBgYHtyICxmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xNX0KSFNELm1hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoSFNELCBtaW4ucGN0ID0gMC4xLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZmMudGhyZXNob2xkID0gMC41LCBvbmx5LnBvcyA9IFQpCnRvcDVtYXJrZXJzIDwtIEhTRC5tYXJrZXJzICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgc2xpY2VfbWF4KG4gPSA1LCBvcmRlcl9ieSA9IGF2Z19sb2dGQykKbWFya2Vyc19oZWF0bWFwIDwtIGRobSh0b3A1bWFya2VycyRnZW5lLCBIU0QpCihtYXJrZXJzX2hlYXRtYXAgKyB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0gMTQsIGNvbG9yID0gImJsYWNrIikpKSU+JQogIGdnc2F2ZShmaWxlbmFtZSA9ICIuL0hTRF9vbmx5L0hTRF9tYXJrZXJnZW5lLnBuZyIsIGRldmljZSA9IHBuZywgaGVpZ2h0ID0gOSwgd2lkdGggPSAxNiwgcGxvdCA9IC4pIApgYGAKCgojIyBkb3RwbG90CmBgYHtyfQp0b3AzbWFya2VycyA8LSBIU0QubWFya2VycyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHNsaWNlX21heChuID0gMywgb3JkZXJfYnkgPSBhdmdfbG9nRkMpCiMjIGRvdHBsb3QgPC0gRG90UGxvdChIU0QsIGZlYXR1cmVzID0gdG9wM21hcmtlcnMkZ2VuZSwgY29scyA9IGMoImxpZ2h0Z3JleSIsIiMjZmYyMTIxIikpICsgY29vcmRfZmxpcCgpICsgUm90YXRlZEF4aXMoKSArIHRoZW1lX2NsYXNzaWMoKSAjI+eUqOadpeiOt+W+l+eZveiJsiDogIzkuI3mmK/pgI/mmI7nmoTog4zmma8KCmRvdHBsb3QgPC0gRG90cGxvdCh0b3AzbWFya2VycyRnZW5lWyFkdXBsaWNhdGVkKHRvcDNtYXJrZXJzJGdlbmUpXSwgSFNEKSArIGNvb3JkX2ZsaXAoKQoKYGBgCgoKCiMj5Lik5Liq5Z+65ZugdW1hcOWFseWumuS9jSAKIyMjIyBSZXR1cm46CmRvdWJsZWdlbmVfZmVhdHVyZXBsb3QKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE1fQpnZW5lX25hbWUgPC0gYygiVG9tIiwicGViIikKcCA8LSBkb3VibGVnZW5lX2ZlYXR1cmVwbG90KGdlbmVfbmFtZSwgSFNEKQpnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZTAoJy4vSFNEX29ubHkvJyxnZW5lX25hbWVbMV0sInZzIixnZW5lX25hbWVbMl0sIi5wbmciKSwgZGV2aWNlID0gcG5nLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDIwLCBwbG90ID0gcCkKYGBgCgojIyDlpJrln7rlm6DloIblj6DlsI/mj5DnkLTlm74gCiMjIyMgUmV0dXJuOgp2aW9saW5fcGxvdApgYGB7ciwgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NH0KdmlvbGluX3Bsb3QoYygic2FsbSIsImtuaSIsIkRsIiwiY3QiLCJ3ZyIsInZuIiwiYnMiKSxIU0QpICU+JQogIGdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMCgiLi9IU0Rfb25seS9IU0RfdmlvbGlucGxvdC5wbmciKSwgZGV2aWNlID0gcG5nLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDUsIHBsb3QgPSAuKQpgYGAKCiMjIOWkmuWbvmZlYXR1cmVwbG90CiMjIyMgUmV0dXJuOgptdWxpdF9mZWF0dXJlcGxvdApgYGB7ciBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQpnZW5lX25hbWUgPC0gYygiYm5sIiwgImJ0bCIsICJodGwiLCAiRWdmciIpICMj5Y+v6KeG5YyW55qE5Z+65Zug5ZCN56ewCm11bHRpX2ZlYXR1cmVwbG90KGdlbmVfbmFtZSwgSFNEKSAlPiUgZ2dzYXZlKHBhc3RlMCgiLi9IU0Rfb25seS8iLGFzLmNoYXJhY3RlcihnZW5lX25hbWUpLCAiLnBuZyIpLGRldmljZSA9IHBuZywgd2lkdGggPSA2LCBoZWlnaHQgPSA1LCBwbG90ID0gLikKCm11bHRpX2ZlYXR1cmVwbG90KGMoInVwZDIiLCJkb21lIiwiUGxleEEiLCJQbGV4QiIpLCBIU0QpICU+JSBnZ3NhdmUoIi4vSFNEX29ubHkvdXBkMmRvbWUucG5nIixkZXZpY2UgPSBwbmcsaGVpZ2h0ID0gNiwgd2lkdGggPSA3LCBwbG90ID0gLikKCm11bHRpX2ZlYXR1cmVwbG90KGMoIlNlbWE1YyIsIlNlbWExYSIsIlNlbWEyYSIsIlNlbWExYiIpLCBIU0QpJT4lIGdnc2F2ZSgiLi9IU0Rfb25seS9zZW1hLnBuZyIsZGV2aWNlID0gcG5nLGhlaWdodCA9IDYsIHdpZHRoID0gNywgcGxvdCA9IC4pCgptdWx0aV9mZWF0dXJlcGxvdChjKCJwZWIiLCJEYWQiLCJkcHAiLCJleCIpLEhTRCkgJT4lIGdnc2F2ZSgiLi9IU0Rfb25seS9wZWJEYWRleC5wbmciLGRldmljZSA9IHBuZyxoZWlnaHQgPSA2LCB3aWR0aCA9IDcsIHBsb3QgPSAuKQpgYGAKCgojIyDovazlvZXlm6DlrZAgU0NFTklDCiMjIyMgUmV0dXJuOgpURmhlYXRtYXAKYGBge3J9CnJlZ3Vsb25BY3Rpdml0eSA8LSByZWFkLmNzdigiLi9yZWd1bG9uQWN0aXZpdHkuY3N2Iixyb3cubmFtZXMgPSAxKQp0b3BURnMgPC0gcmVhZC5jc3YoIi4vdG9wUmVndWxhdG9ycy5jc3YiKQp0b3A1IDwtIHRvcFRGcyAlPiUgZ3JvdXBfYnkoc2V1cmF0Q2x1c3RlcikgJT4lIHNsaWNlX21heChuID0gNSwgb3JkZXJfYnkgPSBSZWxhdGl2ZUFjdGl2aXR5KQoKIyPmoLnmja7lt7Lnn6XnmoR0b3A15pu05paw6KGM6aG65bqPCnJlZ3Vsb25BY3Rpdml0eSA8LSByZWd1bG9uQWN0aXZpdHlbc2FwcGx5KHRvcDUkUmVndWxvbiwgZnVuY3Rpb24oZSkge3doaWNoKHJvd25hbWVzKHJlZ3Vsb25BY3Rpdml0eSkgPT0gZSl9KSwgXQojI2Fubm90YXRpb25fY29sIDwtICBkYXRhLmZyYW1lKGNsdXN0ZXIgPSBmYWN0b3IodG9wNSRzZXVyYXRDbHVzdGVyKSwgcm93Lm5hbWVzID0gbWFrZS5uYW1lcyh0b3A1JFJlZ3Vsb24sVFJVRSkpICMjbWFrZS5uYW1lc+eUqOadpeeUn+aIkOS4jeWGsueqgeeahOihjApyZWd1bG9uQWN0aXZpdHkgPC0gcmVndWxvbkFjdGl2aXR5WyxjKCJEQiIsIkRUIiwiTkUiLCJQQyIsIlNCIiwiVEMiLCJWQiIpXQoKVEZoZWF0bWFwIDwtIHBoZWF0bWFwKHJlZ3Vsb25BY3Rpdml0eSwgYnJlYWtzID0gdW5pcXVlKGMoc2VxKC0zLDMsIGxlbmd0aD00MDApKSksIAogICAgICAgICAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShjKCIjIzFFOTBGRiIsICJ3aGl0ZSIsICIjI2ZmMjEyMSIpKSg0MDApLAogICAgICAgICAgICAgICAgYm9yZGVyX2NvbG9yID0gTkEsIGNsdXN0ZXJfcm93cyA9IEZBTFNFLCBjbHVzdGVyX2NvbHMgPSBGQUxTRSwKICAgICAgICAgICAgICAgIG1haW4gPSAicmVndWxvbkFjdGl2aXR5IixhbmdsZV9jb2wgPSA0NSwgc2hvd19yb3duYW1lcyA9IFQpCiMjZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKCJyZWd1bG9uQWN0aXZpdHkiLCIuc3ZnIiksIGRldmljZSA9IHN2ZywgaGVpZ2h0ID0gOCwgd2lkdGggPSAxMiwgcGxvdCA9IFRGaGVhdG1hcCkKYGBgCgojIyBHTwojIyMjIFJldHVybjoKR09fcGxvdApgYGB7cn0KbGlicmFyeShvcmcuRG0uZWcuZGIpCmZvciAoY2wgaW4gbGV2ZWxzKElkZW50cyhIU0QpKSl7CiAgIyPpgInmi6ljbHVzdGVy5a+55bqU55qEbWFya2VyCiAgZ2VuZV9saXN0IDwtIEhTRC5tYXJrZXJzW0hTRC5tYXJrZXJzJGNsdXN0ZXI9PWNsLF0kZ2VuZQogICMjSUTovazmjaIKICBnZW5lcyA8LSBiaXRyKGdlbmVfbGlzdCwgZnJvbVR5cGU9IlNZTUJPTCIsdG9UeXBlPWMoIkVOVFJFWklEIiwiRU5TRU1CTCIpLAogICAgICAgICAgICAgICAgICAgT3JnRGIgPSBvcmcuRG0uZWcuZGIpCiAgZW5yaWNoLmdvIDwtIGVucmljaEdPKGdlbmUgPSBnZW5lcyRFTlRSRVpJRCwgIyPln7rlm6DliJfooajmlofku7bkuK3nmoTln7rlm6DlkI3np7AKICAgICAgICAgICAgICAgICAgICAgICAgICBPcmdEYiA9IG9yZy5EbS5lZy5kYiwKICAgICAgICAgICAgICAgICAgICAgICAgICBrZXlUeXBlID0gJ0VOVFJFWklEJywKICAgICAgICAgICAgICAgICAgICAgICAgICBvbnQgPSAnQUxMJywgIyPlj6/pgIkgQlDjgIFNRuOAgUND77yM5Lmf5Y+v5Lul5oyH5a6aIEFMTCDlkIzml7borqHnrpcgMyDogIUKICAgICAgICAgICAgICAgICAgICAgICAgICBwQWRqdXN0TWV0aG9kID0gJ2ZkcicsCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHZhbHVlQ3V0b2ZmID0gMC4wNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgcXZhbHVlQ3V0b2ZmID0gMC4yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICByZWFkYWJsZSA9IFRSVUUpCiAgCiAgR09fcGxvdCA8LSBkb3RwbG90KGVucmljaC5nbyx0aXRsZSA9IHBhc3RlKGNsLCJHTyIpLHNob3dDYXRlZ29yeSA9IDE1KSArIHRoZW1lX2NsYXNzaWMoKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gJ2JsYWNrJywgc2l6ZT0xMikpCiAgZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKGNsLCJfR08uc3ZnIiksIGRldmljZSA9IHN2ZywgaGVpZ2h0ID0gOCwgd2lkdGggPSAxMCwgcGxvdCA9IEdPX3Bsb3QpCn0KIyMgYmFycGxvdChlbnJpY2guZ28sc2hvd0NhdGVnb3J5ID0gMTUpICsgdGhlbWVfY2xhc3NpYygpCiMjIGNuZXRwbG90KGVucmljaC5nbykKCmBgYAoKCgpBZGQgYSBuZXcgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpJbnNlcnQgQ2h1bmsqIGJ1dHRvbiBvbiB0aGUgdG9vbGJhciBvciBieSBwcmVzc2luZyAqQ3RybCtBbHQrSSouCgpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkN0cmwrU2hpZnQrSyogdG8gcHJldmlldyB0aGUgSFRNTCBmaWxlKS4KClRoZSBwcmV2aWV3IHNob3dzIHlvdSBhIHJlbmRlcmVkIEhUTUwgY29weSBvZiB0aGUgY29udGVudHMgb2YgdGhlIGVkaXRvci4gQ29uc2VxdWVudGx5LCB1bmxpa2UgKktuaXQqLCAqUHJldmlldyogZG9lcyBub3QgcnVuIGFueSBSIGNvZGUgY2h1bmtzLiBJbnN0ZWFkLCB0aGUgb3V0cHV0IG9mIHRoZSBjaHVuayB3aGVuIGl0IHdhcyBsYXN0IHJ1biBpbiB0aGUgZWRpdG9yIGlzIGRpc3BsYXllZC4K